/*
 * Copyright 2012 Faculty of Informatics - Masaryk University.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cz.muni.fi.pa165.creatures.web;

import cz.muni.fi.pa165.creatures.dto.CreatureDTO;
import cz.muni.fi.pa165.creatures.dto.CreatureTypeDTO;
import cz.muni.fi.pa165.creatures.dto.RegionDTO;
import cz.muni.fi.pa165.creatures.services.CreatureService;
import cz.muni.fi.pa165.creatures.services.CreatureTypeService;
import cz.muni.fi.pa165.creatures.services.RegionService;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sourceforge.stripes.action.DefaultHandler;
import net.sourceforge.stripes.action.DontValidate;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.HandlesEvent;
import net.sourceforge.stripes.action.RedirectResolution;
import net.sourceforge.stripes.action.Resolution;
import net.sourceforge.stripes.action.UrlBinding;
import net.sourceforge.stripes.integration.spring.SpringBean;
import net.sourceforge.stripes.security.action.Secure;
import net.sourceforge.stripes.validation.IntegerTypeConverter;
import net.sourceforge.stripes.validation.LocalizableError;
import net.sourceforge.stripes.validation.Validate;
import net.sourceforge.stripes.validation.ValidateNestedProperties;
import net.sourceforge.stripes.validation.ValidationErrors;

/**
 * @author smikloso
 */
@UrlBinding("/creatures/{$event}/{creatureDTO.id}")
public class CreaturesActionBean extends CreatureHuntingActionBean {

    final static Logger logger =
            Logger.getLogger(CreaturesActionBean.class.getName());

    private List<String> selected;

    @SpringBean
    protected CreatureService creatureService;

    @SpringBean
    protected CreatureTypeService creatureTypeService;

    @SpringBean
    protected RegionService regionService;

    @ValidateNestedProperties(value = {
        @Validate(on = {"/creatures/create"}, field = "name", required = true,
        minlength = 3, maxlength = 256),
        @Validate(converter = IntegerTypeConverter.class, on = {"/creatures/create"},
        field = "weight", required = false, minvalue = 1, maxvalue = 1000),
        @Validate(converter = IntegerTypeConverter.class, on = {"/creatures/create"},
        field = "height", required = false, minvalue = 1, maxvalue = 1000),
        @Validate(converter = IntegerTypeConverter.class, on = {"/creatures/create"},
        field = "actualHitPoints", required = true, minvalue = 0)
    })
    private CreatureDTO creatureDTO;

    public void setCreatureDTO(CreatureDTO creatureDTO) {
        this.creatureDTO = creatureDTO;
    }

    public CreatureDTO getCreatureDTO() {
        return this.creatureDTO;
    }

    public List<String> getSelected() {
        return selected;
    }

    public void setSelected(List<String> selected) {
        this.selected = selected;
    }

    @DefaultHandler
    public Resolution all() {
        logger.log(Level.INFO, "all()");
        return new ForwardResolution("/creatures_show.jsp");
    }

    @Secure(roles = "admin")
    public Resolution create() {
        logger.log(Level.INFO, "create()");
        return new ForwardResolution("/creatures_create.jsp");
    }

    @Secure(roles = "admin")
    @HandlesEvent("add")
    public Resolution add() {
        logger.log(Level.INFO, "add() {0}", creatureDTO.toString());
        if (creatureDTO == null || creatureDTO.getName() == null) {
            ValidationErrors errors = new ValidationErrors();
            errors.add("name", new LocalizableError("creature.name_not_set"));
            getContext().setValidationErrors(errors);
            return getContext().getSourcePageResolution();
        }
        CreatureTypeDTO creatureTypeDTO = null;
        
        if (creatureDTO.getCreatureTypeDTO() != null) {
            creatureTypeDTO = creatureTypeService.getById(
                    Long.parseLong(creatureDTO.getCreatureTypeDTO().getId()));
            creatureDTO.setCreatureTypeDTO(null);
            if (creatureDTO.getActualHitPoints() > creatureTypeDTO.getMaxHitPoints()) {
                creatureDTO.setActualHitPoints(creatureTypeDTO.getMaxHitPoints());
            }
        }
        RegionDTO regionDTO = null;
        if (creatureDTO.getRegionDTO() != null) {
            regionDTO = regionService.getById(
                    Long.parseLong(creatureDTO.getRegionDTO().getId()));
            creatureDTO.setRegionDTO(null);
        }

        creatureDTO.setId(creatureService.create(creatureDTO).toString());

        CreatureDTO dto = creatureService.getById(Long.parseLong(creatureDTO.getId()));
        dto.setCreatureTypeDTO(creatureTypeDTO);
        dto.setRegionDTO(regionDTO);
        creatureService.update(dto);
        return new RedirectResolution(this.getClass(), "all");
    }

    @Secure(roles = "admin")
    public Resolution deleteall() {
        logger.log(Level.INFO, "deleteAll()");
        creatureService.deleteAll();
        return new ForwardResolution("/creatures_show.jsp");
    }

    public List<CreatureDTO> getAll() {
        logger.log(Level.INFO, "getAll()");
        return creatureService.getAll();
    }

    public Long getCount() {
        logger.log(Level.INFO, "getCount()");
        return creatureService.getCount();
    }

    @Secure(roles = "admin")
    public Resolution save() {
        logger.log(Level.INFO, "save({0})", creatureDTO.getId());
        if (creatureDTO.getCreatureTypeDTO() != null) {
            CreatureTypeDTO creatureTypeDTO = creatureTypeService.getById(
                    Long.parseLong(creatureDTO.getCreatureTypeDTO().getId()));
            creatureDTO.setCreatureTypeDTO(creatureTypeDTO);
            if (creatureDTO.getActualHitPoints() > creatureTypeDTO.getMaxHitPoints()) {
                creatureDTO.setActualHitPoints(creatureTypeDTO.getMaxHitPoints());
            }
        }
        if (creatureDTO.getRegionDTO() != null) {
            RegionDTO regionDTO = regionService.getById(
                    Long.parseLong(creatureDTO.getRegionDTO().getId()));
            creatureDTO.setRegionDTO(regionDTO);
        }
        creatureService.update(creatureDTO);
        return new ForwardResolution("/creatures_show.jsp");
    }

    @Secure(roles = "admin")
    public Resolution remove() {
        logger.log(Level.INFO, "delete({0})", creatureDTO.getId());
        creatureService.remove(creatureDTO);
        return new RedirectResolution(this.getClass());
    }

    public Resolution detail() {
        creatureDTO = creatureService.getById(Long.parseLong(creatureDTO.getId()));
        return new ForwardResolution("/creatures_detail.jsp");
    }

    @Secure(roles = "admin")
    public Resolution edit() {
        creatureDTO = creatureService.getById(Long.parseLong(creatureDTO.getId()));
        return new ForwardResolution("/creatures_edit.jsp");
    }

    @Secure(roles = "admin")
    public Resolution deleteSelected() {
        if (selected != null) {
            for (String id : selected) {
                CreatureDTO selectedCreatures = creatureService.getById(Long.parseLong(id));
                if (selectedCreatures != null) {
                    creatureService.remove(selectedCreatures);
                }
            }
        }
        return new ForwardResolution("/creatures_show.jsp");
    }

    @DontValidate
    public Resolution cancel() {
        logger.log(Level.INFO, "cancel weapon");
        return new RedirectResolution(this.getClass(), "all");
    }
    public List<RegionDTO> getAllRegions() {
        return regionService.getAll();
    }

    public List<CreatureTypeDTO> getAllCreatureTypes() {
        return creatureTypeService.getAll();
    }
}
